/* * Sun Public License Notice * * The contents of this file are subject to the Sun Public License * Version 1.0 (the "License"). You may not use this file except in * compliance with the License. A copy of the License is available at * http://www.sun.com/ * * The Original Code is NetBeans. The Initial Developer of the Original * Code is Sun Microsystems, Inc. Portions Copyright 1997-2001 Sun * Microsystems, Inc. All Rights Reserved. */ package org.netbeans.modules.corba; import java.beans.PropertyChangeListener; import java.beans.PropertyChangeEvent; import java.io.*; import java.lang.reflect.*; import java.util.Iterator; import java.text.MessageFormat; import javax.swing.event.DocumentListener; import javax.swing.event.DocumentEvent; import javax.swing.event.ChangeListener; import javax.swing.event.ChangeEvent; import javax.swing.Timer; import javax.swing.text.Document; import javax.swing.text.StyledDocument; import javax.swing.text.EditorKit; import javax.swing.text.BadLocationException; import org.openide.util.WeakListener; import org.openide.util.NbBundle; import org.openide.util.Task; import org.openide.util.TaskListener; import org.openide.util.RequestProcessor; import org.openide.text.EditorSupport; import org.openide.text.PositionRef; import org.openide.cookies.EditCookie; import org.openide.cookies.SaveCookie; import org.openide.cookies.OpenCookie; import org.openide.loaders.MultiDataObject; import org.openide.loaders.DataObject; import org.openide.filesystems.FileObject; import org.openide.windows.CloneableTopComponent; import org.openide.windows.TopComponent; import org.openide.nodes.NodeAdapter; import org.openide.nodes.Node; import org.openide.TopManager; import org.openide.NotifyDescriptor; import org.netbeans.modules.corba.settings.CORBASupportSettings; /** Support for viewing porperties files (EditCookie) by opening them in a text editor */ public class IDLEditorSupport extends EditorSupport implements EditCookie { //, Serializable { //public static final boolean DEBUG = true; public static final boolean DEBUG = false; /** Timer which countdowns the auto-reparsing time. */ javax.swing.Timer timer; /** New lines in this file was delimited by '\n' */ static final byte NEW_LINE_N = 0; /** New lines in this file was delimited by '\r' */ static final byte NEW_LINE_R = 1; /** New lines in this file was delimited by '\r\n' */ static final byte NEW_LINE_RN = 2; /** The type of new lines */ byte newLineType = NEW_LINE_N; /** The flag saying if we should listen to the document modifications */ private boolean listenToEntryModifs = true; private Document listenDocument; /** Listener to the document changes - entry. The superclass holds a saving manager * for the whole dataobject. */ //private EntrySavingManager entryModifL; /** Properties Settings */ CORBASupportSettings settings; static final long serialVersionUID =1787354011149868490L; /** Constructor */ MultiDataObject.Entry idl_file; private PositionRef position; public IDLEditorSupport(MultiDataObject.Entry entry) { super (entry); if (DEBUG) System.out.println ("IDLEditorSupport(" + entry + ");"); idl_file = entry; //System.out.println("editor support constructor - " + entry.getFile().getName()); //Thread.dumpStack(); //initialize(); } /* public void initialize() { myEntry = (MultiDataObject.Entry)entry; super.setModificationListening(false); //setMIMEType (IDLDataObject.MIME_PROPERTIES); //initTimer(); // listen to myself so I can add a listener for changes when the document is loaded addChangeListener(new ChangeListener() { public void stateChanged(ChangeEvent evt) { if (isDocumentLoaded()) { //setListening(true); } } }); //PENDING // set actions //setActions (new SystemAction [] { // SystemAction.get (CutAction.class), // SystemAction.get (CopyAction.class), // SystemAction.get (PasteAction.class), //}); } */ void setRef(CloneableTopComponent.Ref ref) { allEditors = ref; } //Object writeReplace() throws ObjectStreamException { // return new SerialProxy(myEntry); //} /* public static class SerialProxy implements Serializable { static final long serialVersionUID =2675098551717845346L; public SerialProxy (MultiDataObject.Entry serialEntry) { this.serialEntry = serialEntry; } private MultiDataObject.Entry serialEntry; //Object readResolve() throws ObjectStreamException { //System.out.println("deserializing properties editor"); //System.out.println("serialEntry " + serialEntry); //System.out.println("dataobject " + serialEntry.getDataObject()); //Thread.dumpStack(); //Object pe = serialEntry.getIDLEditor(); //System.out.println("deserializing properties editor END"); //return pe; //} } */ /** Visible view of underlying file entry */ //transient MultiDataObject.Entry myEntry; /** Focuses existing component to open, or if none exists creates new. * @see OpenCookie#open */ public EditorSupport.Editor openAt (PositionRef pos) { if (DEBUG) System.out.println ("openAt (" + pos + ");"); return super.openAt (pos); } public void open () { int line = 1; int column = 1; if (DEBUG) System.out.println ("open ();"); IDLDataObject ido = (IDLDataObject)idl_file.getDataObject (); if (ido != null) { //position = ido.getPositionRef (); line = ido.getLinePosition (); column = ido.getColumnPosition () + 1; } /* if (position != null) { PositionRef tmp_pos = position; position = null; openAt (tmp_pos); } */ if (line > 1 & column > 1) { ido.setLinePosition (1); ido.setColumnPosition (1); ido.openAtPosition (line, column); } //else { CloneableTopComponent editor = openCloneableTopComponent2(); editor.requestFocus(); //y} } /** Simply open for an editor. */ protected final CloneableTopComponent openCloneableTopComponent2() { if (DEBUG) System.out.println("openCloneableTopComponent2()"); MessageFormat mf = new MessageFormat (NbBundle.getBundle(IDLEditorSupport.class). getString ("CTL_IDL_OPEN")); synchronized (allEditors) { try { CloneableTopComponent ret = (CloneableTopComponent)allEditors.getAnyComponent (); ret.open(); return ret; } catch (java.util.NoSuchElementException ex) { // no opened editor TopManager.getDefault ().setStatusText (mf.format (new Object[] {entry.getFile().getName()})); CloneableTopComponent editor = createCloneableTopComponent (); allEditors = editor.getReference (); editor.open(); TopManager.getDefault ().setStatusText (NbBundle.getBundle(IDLEditorSupport.class).getString ("CTL_IDL_OPENED")); return editor; } } } /** Launches the timer for autoreparse */ /* private void initTimer() { // initialize timer timer = new Timer(0, new java.awt.event.ActionListener() { public void actionPerformed(java.awt.event.ActionEvent e) { myEntry.getHandler().autoParse(); } }); timer.setInitialDelay(settings.getAutoParsingDelay()); timer.setRepeats(false); } */ /** Returns whether there is an open component (editor or open). */ /* public synchronized boolean hasOpenComponent() { return (hasOpenTableComponent() || hasOpenEditorComponent()); } */ /* private synchronized boolean hasOpenTableComponent() { //System.out.println("hasOpenComponent (table) " + myEntry.getFile().getPackageNameExt('/','.') + " " + ((IDLDataObject)myEntry.getDataObject()).getOpenSupport().hasOpenComponent()); return ((IDLDataObject)myEntry.getDataObject()).getOpenSupport().hasOpenComponent(); } */ /** Returns whether there is an open editor component. */ /* public synchronized boolean hasOpenEditorComponent() { java.util.Enumeration en = allEditors.getComponents (); //System.out.println("hasOpenComponent (editor) " + myEntry.getFile().getPackageNameExt('/','.') + " " + en.hasMoreElements ()); return en.hasMoreElements (); } */ /* public void saveThisEntry() throws IOException { super.saveDocument(); myEntry.setModified(false); } */ /* public boolean close() { SaveCookie savec = (SaveCookie) myEntry.getCookie(SaveCookie.class); if ((savec != null) && hasOpenTableComponent()) { return false; } //System.out.println("closing"); if (!super.close()) return false; //System.out.println("closed - document open = " + isDocumentLoaded()); closeDocumentEntry(); myEntry.getHandler().reparseNowBlocking(); return true; } */ /** Clears all data from memory. */ /* protected void closeDocument () { super.closeDocument(); closeDocumentEntry(); } */ /** Utility method which enables or disables listening to modifications * on asociated document. * <P> * Could be useful if we have to modify document, but do not want the * Save and Save All actions to be enabled/disabled automatically. * Initially modifications are listened to. * @param listenToModifs whether to listen to modifications */ /* public void setModificationListening (final boolean listenToModifs) { //System.out.println("set modification listening - " + listenToModifs); this.listenToEntryModifs = listenToModifs; if (getDocument() == null) return; //setListening(listenToEntryModifs); } */ /* A method to create a new component. Overridden in subclasses. * @return the {@link Editor} for this support */ protected CloneableTopComponent createCloneableTopComponent () { // initializes the document if not initialized if (DEBUG) System.out.println ("createCloneableTopComponent ()"); prepareDocument (); DataObject obj = idl_file.getDataObject (); Editor editor = new IDLEditor (obj, this); return editor; } /** Should test whether all data is saved, and if not, prompt the user * to save. Called by my topcomponent when it wants to close its last topcomponent, but the table editor may still be open * * @return <code>true</code> if everything can be closed */ /* protected boolean canClose () { SaveCookie savec = (SaveCookie) myEntry.getCookie(SaveCookie.class); if (savec != null) { // if the table is open, can close without worries, don't remove the save cookie if (hasOpenTableComponent()) return true; // PENDING - is not thread safe MessageFormat format = new MessageFormat(NbBundle.getBundle(IDLEditorSupport.class). getString("MSG_SaveFile")); String msg = format.format(new Object[] { entry.getFile().getName()}); NotifyDescriptor nd = new NotifyDescriptor.Confirmation(msg, NotifyDescriptor.YES_NO_CANCEL_OPTION); Object ret = TopManager.getDefault().notify(nd); // cancel if (NotifyDescriptor.CANCEL_OPTION.equals(ret)) return false; // yes if (NotifyDescriptor.YES_OPTION.equals(ret)) { try { savec.save(); } catch (IOException e) { TopManager.getDefault().notifyException(e); return false; } } // no if (NotifyDescriptor.NO_OPTION.equals(ret)) { return true; } } return true; } */ /** Read the file from the stream, filter the guarded section * comments, and mark the sections in the editor. * * @param doc the document to read into * @param stream the open stream to read from * @param kit the associated editor kit * @throws IOException if there was a problem reading the file * @throws BadLocationException should not normally be thrown * @see #saveFromKitToStream */ /* protected void loadFromStreamToKit (StyledDocument doc, InputStream stream, EditorKit kit) throws IOException, BadLocationException { NewLineInputStream is = new NewLineInputStream(stream); try { kit.read(is, doc, 0); newLineType = is.getNewLineType(); } finally { is.close(); } } */ /** Store the document and add the special comments signifying * guarded sections. * * @param doc the document to write from * @param kit the associated editor kit * @param stream the open stream to write to * @throws IOException if there was a problem writing the file * @throws BadLocationException should not normally be thrown * @see #loadFromStreamToKit */ /* protected void saveFromKitToStream(StyledDocument doc, EditorKit kit, OutputStream stream) throws IOException, BadLocationException { //System.out.println("saving - doc = " + doc); OutputStream os = new NewLineOutputStream(stream, newLineType); try { kit.write(os, doc, 0, doc.getLength()); } finally { if (os != null) { try { os.close(); } catch (IOException e) { } } } } */ /** Does part of the cleanup - removes a listener. */ /* private void closeDocumentEntry () { // listen to modifs if (listenToEntryModifs) { getEntryModifL().clearSaveCookie(); setListening(false); } } */ /* private void setListening(boolean listen) { if (listen) { if ((getDocument() == null) || (listenDocument == getDocument())) return; if (listenDocument != null) // also holds that listenDocument != getDocument() listenDocument.removeDocumentListener(getEntryModifL()); listenDocument = getDocument(); listenDocument.addDocumentListener(getEntryModifL()); } else { if (listenDocument != null) { listenDocument.removeDocumentListener(getEntryModifL()); listenDocument = null; } } } */ /** Visible view of the underlying method. */ /* public Editor openAt(PositionRef pos) { return super.openAt(pos); } */ /** Returns a EditCookie for editing at a given position. */ /* public IDLEditAt getViewerAt(String key) { return new IDLEditAt (key); } */ /** Class for opening at a given key. */ /* public class IDLEditAt implements EditCookie { private String key; IDLEditAt(String key) { this.key = key; } public void setKey(String key) { this.key = key; } public String getKey() { return key; } public void edit() { Element.ItemElem item = myEntry.getHandler().getStructure().getItem(key); if (item != null) { PositionRef pos = item.getKeyElem().getBounds().getBegin(); IDLEditorSupport.this.openAt(pos); } else { IDLEditorSupport.this.edit(); //} } } */ /* private synchronized EntrySavingManager getEntryModifL () { if (entryModifL == null) { entryModifL = new EntrySavingManager(); // listens whether to add or remove SaveCookie myEntry.addPropertyChangeListener(entryModifL); } return entryModifL; } String getModifiedAppendix() { return modifiedAppendix; } */ /** Cloneable top component to hold the editor kit. */ public static class IDLEditor extends EditorSupport.Editor { protected transient MultiDataObject.Entry entry; private transient IDLEditorSupport propSupport; private transient PropertyChangeListener saveCookieLNode; private transient NodeAdapter nodeL; static final long serialVersionUID =-2702087884943509637L; public IDLEditor() { super(); if (DEBUG) System.out.println("IDLEditor"); } public IDLEditor(DataObject obj, IDLEditorSupport support) { super(obj, support); if (DEBUG) System.out.println("IDLEditor (" + obj + ", " + support + ");"); this.propSupport = support; initMe(); } private void initMe() { this.entry = propSupport.idl_file; // add to EditorSupport - patch for a bug in deserialization propSupport.setRef(getReference()); /* entry.getNodeDelegate().addNodeListener ( new WeakListener.Node(nodeL = new NodeAdapter () { public void propertyChange (PropertyChangeEvent ev) { if (ev.getPropertyName ().equals (Node.PROP_DISPLAY_NAME)) { updateName(); } } } )); */ Node n = entry.getDataObject ().getNodeDelegate (); setActivatedNodes (new Node[] { n }); //updateName(); // entry to the set of listeners /* saveCookieLNode = new PropertyChangeListener() { public void propertyChange(PropertyChangeEvent evt) { if (PresentableFileEntry.PROP_COOKIE.equals(evt.getPropertyName()) || PresentableFileEntry.PROP_NAME.equals(evt.getPropertyName())) { updateName(); } } }; this.entry.addPropertyChangeListener( new WeakListener.PropertyChange(saveCookieLNode)); } */ } /** When closing last view, also close the document. * @return <code>true</code> if close succeeded */ /* protected boolean closeLast () { // instead of super if (!propSupport.canClose ()) { // if we cannot close the last window return false; } boolean doCloseDoc = !propSupport.hasOpenTableComponent(); //SaveCookie savec = (SaveCookie) entry.getCookie(SaveCookie.class); try { if (doCloseDoc) { // propSupport.closeDocument (); by reflection Method closeDoc = EditorSupport.class.getDeclaredMethod("closeDocument", new Class[0]); closeDoc.setAccessible(true); closeDoc.invoke(propSupport, new Object[0]); } //if (propSupport.lastSelected == this) { //propSupport.lastSelected = null; by reflection Field lastSel = EditorSupport.class.getDeclaredField("lastSelected"); lastSel.setAccessible(true); if (lastSel.get(propSupport) == this) lastSel.set(propSupport, null); } catch (Exception e) { if (Boolean.getBoolean("netbeans.debug.exceptions")) e.printStackTrace(); } // end super //boolean canClose = super.closeLast(); //if (!canClose) //return false; if (doCloseDoc) { propSupport.closeDocumentEntry(); entry.getHandler().reparseNowBlocking(); } return true; } */ /** Updates the name of this top component according to * the existence of the save cookie in ascoiated data object */ /* protected void updateName () { if (entry == null) { setName(""); return; } else { String name = entry.getFile().getName(); if (entry.getCookie(SaveCookie.class) != null) setName(name + propSupport.getModifiedAppendix()); else setName(name); } } public void writeExternal (ObjectOutput out) throws IOException { super.writeExternal(out); out.writeObject(propSupport); } public void readExternal (ObjectInput in) throws IOException, ClassNotFoundException { super.readExternal(in); propSupport = (IDLEditorSupport)in.readObject(); initMe(); } } // end of IDLEditor inner class */ /** EntrySavingManager manages two tasks concerning saving:<P> * 1) It tracks changes in document asociated with ther entry and * sets modification flag appropriately.<P> * 2) This class also implements functionality of SaveCookie interface */ /* private final class EntrySavingManager implements DocumentListener, SaveCookie, PropertyChangeListener { public void changedUpdate(DocumentEvent ev) { // do nothing - just an attribute } public void insertUpdate(DocumentEvent ev) { modified(); changeStructureStatus(); } public void removeUpdate(DocumentEvent ev) { modified(); changeStructureStatus(); } private void changeStructureStatus() { int delay = settings.getAutoParsingDelay(); myEntry.getHandler().setDirty(true); if (delay > 0) { timer.setInitialDelay(delay); timer.restart(); } } public void propertyChange(PropertyChangeEvent ev) { if ((ev.getSource() == myEntry) && (IDLFileEntry.PROP_MODIFIED.equals(ev.getPropertyName()))) { if (((Boolean) ev.getNewValue()).booleanValue()) { addSaveCookie(); } else { removeSaveCookie(); } } } public void save () throws IOException { // do saving job saveThisEntry(); } void clearSaveCookie() { // remove save cookie (if save was succesfull) myEntry.setModified(false); } private void modified () { myEntry.setModified(true); } private void addSaveCookie() { if (myEntry.getCookie(SaveCookie.class) == null) { myEntry.getCookieSet().add(this); } ((IDLDataObject)myEntry.getDataObject()).updateModificationStatus(); if (!hasOpenComponent()) { RequestProcessor.postRequest(new Runnable() { public void run() { myEntry.getIDLEditor().open(); } }); } } private void removeSaveCookie() { // remove Save cookie from the data object if (myEntry.getCookie(SaveCookie.class) == this) { myEntry.getCookieSet().remove(this); } ((IDLDataObject)myEntry.getDataObject()).updateModificationStatus(); } } // end of EntrySavingManager inner class static class NewLineInputStream extends InputStream { BufferedInputStream bufis; int nextToRead; int[] newLineTypes; public NewLineInputStream(InputStream is) throws IOException { bufis = new BufferedInputStream(is); nextToRead = bufis.read(); newLineTypes = new int[] { 0, 0, 0 }; } public int read() throws IOException { if (nextToRead == -1) return -1; if (nextToRead == '\r') { nextToRead = bufis.read(); while (nextToRead == '\r') nextToRead = bufis.read(); if (nextToRead == '\n') { nextToRead = bufis.read(); newLineTypes[NEW_LINE_RN]++; return '\n'; } else { newLineTypes[NEW_LINE_R]++; return '\n'; } } if (nextToRead == '\n') { nextToRead = bufis.read(); newLineTypes[NEW_LINE_N]++; return '\n'; } int oldNextToRead = nextToRead; nextToRead = bufis.read(); return oldNextToRead; } public byte getNewLineType() { if (newLineTypes[0] > newLineTypes[1]) { return (newLineTypes[0] > newLineTypes[2]) ? (byte) 0 : 2; } else { return (newLineTypes[1] > newLineTypes[2]) ? (byte) 1 : 2; } } } static class NewLineOutputStream extends OutputStream { OutputStream stream; byte newLineType; public NewLineOutputStream(OutputStream stream, byte newLineType) { this.stream = stream; this.newLineType = newLineType; } public void write(int b) throws IOException { if (b == '\r') return; if (b == '\n') { switch (newLineType) { case NEW_LINE_R: stream.write('\r'); break; case NEW_LINE_RN: stream.write('\r'); case NEW_LINE_N: stream.write('\n'); break; } } else { stream.write(b); } } public void close() throws IOException { stream.flush(); stream.close(); } */ } }